/*
**  UDP/IP for LPC17XX
**  July 2011
**  Aart Janse van den Bosch
**  portions (lots of em) copied from code red and adjusted where needed.
**  Aout 2012, adapte pour Keil uVision, jea
*/
#include <stdio.h>
#include "string.h"
#include "udpip.h"
#include "LPC17xx.h"

// used a lot in ethernet packages, since most values inside ethernet
// packets are stored in Big Endian format, while LPC17xx is mostly
// running in Little Endian format.
#define SWAPB(Word)          ((unsigned short)((Word) << 8) | ((Word) >> 8))
#define DEFAULT_TTL          64                  // Time To Live sent with packets
// ------------- Ethernet Media Access Controller (EMAC) ----------------------
#define ETH_MAX_FLEN        1536        /* Max. Ethernet Frame Size          */
/* MAC Configuration Register 1 */
#define MAC1_REC_EN         0x00000001  /* Receive Enable                    */
#define MAC1_PASS_ALL       0x00000002  /* Pass All Receive Frames           */
#define MAC1_RX_FLOWC       0x00000004  /* RX Flow Control                   */
#define MAC1_TX_FLOWC       0x00000008  /* TX Flow Control                   */
#define MAC1_LOOPB          0x00000010  /* Loop Back Mode                    */
#define MAC1_RES_TX         0x00000100  /* Reset TX Logic                    */
#define MAC1_RES_MCS_TX     0x00000200  /* Reset MAC TX Control Sublayer     */
#define MAC1_RES_RX         0x00000400  /* Reset RX Logic                    */
#define MAC1_RES_MCS_RX     0x00000800  /* Reset MAC RX Control Sublayer     */
#define MAC1_SIM_RES        0x00004000  /* Simulation Reset                  */
#define MAC1_SOFT_RES       0x00008000  /* Soft Reset MAC                    */
/* MAC Configuration Register 2 */
#define MAC2_FULL_DUP       0x00000001  /* Full Duplex Mode                  */
#define MAC2_FRM_LEN_CHK    0x00000002  /* Frame Length Checking             */
#define MAC2_HUGE_FRM_EN    0x00000004  /* Huge Frame Enable                 */
#define MAC2_DLY_CRC        0x00000008  /* Delayed CRC Mode                  */
#define MAC2_CRC_EN         0x00000010  /* Append CRC to every Frame         */
#define MAC2_PAD_EN         0x00000020  /* Pad all Short Frames              */
#define MAC2_VLAN_PAD_EN    0x00000040  /* VLAN Pad Enable                   */
#define MAC2_ADET_PAD_EN    0x00000080  /* Auto Detect Pad Enable            */
#define MAC2_PPREAM_ENF     0x00000100  /* Pure Preamble Enforcement         */
#define MAC2_LPREAM_ENF     0x00000200  /* Long Preamble Enforcement         */
#define MAC2_NO_BACKOFF     0x00001000  /* No Backoff Algorithm              */
#define MAC2_BACK_PRESSURE  0x00002000  /* Backoff Presurre / No Backoff     */
#define MAC2_EXCESS_DEF     0x00004000  /* Excess Defer                      */
/* Back-to-Back Inter-Packet-Gap Register */
#define IPGT_FULL_DUP       0x00000015  /* Recommended value for Full Duplex */
#define IPGT_HALF_DUP       0x00000012  /* Recommended value for Half Duplex */
/* Non Back-to-Back Inter-Packet-Gap Register */
#define IPGR_DEF            0x00000012  /* Recommended value                 */
/* Collision Window/Retry Register */
#define CLRT_DEF            0x0000370F  /* Default value                     */
/* PHY Support Register */
#define SUPP_SPEED          0x00000100  /* Reduced MII Logic Current Speed   */

/* Test Register */
#define TEST_SHCUT_PQUANTA  0x00000001  /* Shortcut Pause Quanta             */
#define TEST_TST_PAUSE      0x00000002  /* Test Pause                        */
#define TEST_TST_BACKP      0x00000004  /* Test Back Pressure                */

/* MII Management Configuration Register */
#define MCFG_SCAN_INC       0x00000001  /* Scan Increment PHY Address        */
#define MCFG_SUPP_PREAM     0x00000002  /* Suppress Preamble                 */
#define MCFG_CLK_SEL        0x0000003C  /* Clock Select Mask                 */
#define MCFG_RES_MII        0x00008000  /* Reset MII Management Hardware     */

#define MCFG_CLK_DIV28      0x0000001C  /* MDC = hclk / 28 */
#define MCFG_CLK_DIV36      0x00000020
#define MCFG_CLK_DIV48    0x0000002c
#define MCFG_CLK_DIV64    0x0000003c

/* MII Management Command Register */
#define MCMD_READ           0x00000001  /* MII Read                          */
#define MCMD_SCAN           0x00000002  /* MII Scan continuously             */

#define MII_WR_TOUT         0x00050000  /* MII Write timeout count           */
#define MII_RD_TOUT         0x00050000  /* MII Read timeout count            */

/* MII Management Address Register */
#define MADR_REG_ADR        0x0000001F  /* MII Register Address Mask         */
#define MADR_PHY_ADR        0x00001F00  /* PHY Address Mask                  */

/* MII Management Indicators Register */
#define MIND_BUSY           0x00000001  /* MII is Busy                       */
#define MIND_SCAN           0x00000002  /* MII Scanning in Progress          */
#define MIND_NOT_VAL        0x00000004  /* MII Read Data not valid           */
#define MIND_MII_LINK_FAIL  0x00000008  /* MII Link Failed                   */

/* Command Register */
#define CR_RX_EN            0x00000001  /* Enable Receive                    */
#define CR_TX_EN            0x00000002  /* Enable Transmit                   */
#define CR_REG_RES          0x00000008  /* Reset Host Registers              */
#define CR_TX_RES           0x00000010  /* Reset Transmit Datapath           */
#define CR_RX_RES           0x00000020  /* Reset Receive Datapath            */
#define CR_PASS_RUNT_FRM    0x00000040  /* Pass Runt Frames                  */
#define CR_PASS_RX_FILT     0x00000080  /* Pass RX Filter                    */
#define CR_TX_FLOW_CTRL     0x00000100  /* TX Flow Control                   */
#define CR_RMII             0x00000200  /* Reduced MII Interface             */
#define CR_FULL_DUP         0x00000400  /* Full Duplex                       */

/* Status Register */
#define SR_RX_EN            0x00000001  /* Enable Receive                    */
#define SR_TX_EN            0x00000002  /* Enable Transmit                   */

/* Transmit Status Vector 0 Register */
#define TSV0_CRC_ERR        0x00000001  /* CRC error                         */
#define TSV0_LEN_CHKERR     0x00000002  /* Length Check Error                */
#define TSV0_LEN_OUTRNG     0x00000004  /* Length Out of Range               */
#define TSV0_DONE           0x00000008  /* Transmission Completed            */
#define TSV0_MCAST          0x00000010  /* Multicast Destination             */
#define TSV0_BCAST          0x00000020  /* Broadcast Destination             */
#define TSV0_PKT_DEFER      0x00000040  /* Packet Deferred                   */
#define TSV0_EXC_DEFER      0x00000080  /* Excessive Packet Deferral         */
#define TSV0_EXC_COLL       0x00000100  /* Excessive Collision               */
#define TSV0_LATE_COLL      0x00000200  /* Late Collision Occured            */
#define TSV0_GIANT          0x00000400  /* Giant Frame                       */
#define TSV0_UNDERRUN       0x00000800  /* Buffer Underrun                   */
#define TSV0_BYTES          0x0FFFF000  /* Total Bytes Transferred           */
#define TSV0_CTRL_FRAME     0x10000000  /* Control Frame                     */
#define TSV0_PAUSE          0x20000000  /* Pause Frame                       */
#define TSV0_BACK_PRESS     0x40000000  /* Backpressure Method Applied       */
#define TSV0_VLAN           0x80000000  /* VLAN Frame                        */

/* Transmit Status Vector 1 Register */
#define TSV1_BYTE_CNT       0x0000FFFF  /* Transmit Byte Count               */
#define TSV1_COLL_CNT       0x000F0000  /* Transmit Collision Count          */

/* Receive Status Vector Register */
#define RSV_BYTE_CNT        0x0000FFFF  /* Receive Byte Count                */
#define RSV_PKT_IGNORED     0x00010000  /* Packet Previously Ignored         */
#define RSV_RXDV_SEEN       0x00020000  /* RXDV Event Previously Seen        */
#define RSV_CARR_SEEN       0x00040000  /* Carrier Event Previously Seen     */
#define RSV_REC_CODEV       0x00080000  /* Receive Code Violation            */
#define RSV_CRC_ERR         0x00100000  /* CRC Error                         */
#define RSV_LEN_CHKERR      0x00200000  /* Length Check Error                */
#define RSV_LEN_OUTRNG      0x00400000  /* Length Out of Range               */
#define RSV_REC_OK          0x00800000  /* Frame Received OK                 */
#define RSV_MCAST           0x01000000  /* Multicast Frame                   */
#define RSV_BCAST           0x02000000  /* Broadcast Frame                   */
#define RSV_DRIB_NIBB       0x04000000  /* Dribble Nibble                    */
#define RSV_CTRL_FRAME      0x08000000  /* Control Frame                     */
#define RSV_PAUSE           0x10000000  /* Pause Frame                       */
#define RSV_UNSUPP_OPC      0x20000000  /* Unsupported Opcode                */
#define RSV_VLAN            0x40000000  /* VLAN Frame                        */

/* Flow Control Counter Register */
#define FCC_MIRR_CNT        0x0000FFFF  /* Mirror Counter                    */
#define FCC_PAUSE_TIM       0xFFFF0000  /* Pause Timer                       */

/* Flow Control Status Register */
#define FCS_MIRR_CNT        0x0000FFFF  /* Mirror Counter Current            */

/* Receive Filter Control Register */
#define RFC_UCAST_EN        0x00000001  /* Accept Unicast Frames Enable      */
#define RFC_BCAST_EN        0x00000002  /* Accept Broadcast Frames Enable    */
#define RFC_MCAST_EN        0x00000004  /* Accept Multicast Frames Enable    */
#define RFC_UCAST_HASH_EN   0x00000008  /* Accept Unicast Hash Filter Frames */
#define RFC_MCAST_HASH_EN   0x00000010  /* Accept Multicast Hash Filter Fram.*/
#define RFC_PERFECT_EN      0x00000020  /* Accept Perfect Match Enable       */
#define RFC_MAGP_WOL_EN     0x00001000  /* Magic Packet Filter WoL Enable    */
#define RFC_PFILT_WOL_EN    0x00002000  /* Perfect Filter WoL Enable         */

/* Receive Filter WoL Status/Clear Registers */
#define WOL_UCAST           0x00000001  /* Unicast Frame caused WoL          */
#define WOL_BCAST           0x00000002  /* Broadcast Frame caused WoL        */
#define WOL_MCAST           0x00000004  /* Multicast Frame caused WoL        */
#define WOL_UCAST_HASH      0x00000008  /* Unicast Hash Filter Frame WoL     */
#define WOL_MCAST_HASH      0x00000010  /* Multicast Hash Filter Frame WoL   */
#define WOL_PERFECT         0x00000020  /* Perfect Filter WoL                */
#define WOL_RX_FILTER       0x00000080  /* RX Filter caused WoL              */
#define WOL_MAG_PACKET      0x00000100  /* Magic Packet Filter caused WoL    */

/* Interrupt Status/Enable/Clear/Set Registers */
#define INT_RX_OVERRUN      0x00000001  /* Overrun Error in RX Queue         */
#define INT_RX_ERR          0x00000002  /* Receive Error                     */
#define INT_RX_FIN          0x00000004  /* RX Finished Process Descriptors   */
#define INT_RX_DONE         0x00000008  /* Receive Done                      */
#define INT_TX_UNDERRUN     0x00000010  /* Transmit Underrun                 */
#define INT_TX_ERR          0x00000020  /* Transmit Error                    */
#define INT_TX_FIN          0x00000040  /* TX Finished Process Descriptors   */
#define INT_TX_DONE         0x00000080  /* Transmit Done                     */
#define INT_SOFT_INT        0x00001000  /* Software Triggered Interrupt      */
#define INT_WAKEUP          0x00002000  /* Wakeup Event Interrupt            */

/* Power Down Register */
#define PD_POWER_DOWN       0x80000000  /* Power Down MAC                    */

/* ENET Device Revision ID */
#define OLD_EMAC_MODULE_ID  0x39022000  /* Rev. ID for first rev '-'         */

/* DP83848C PHY Registers */
#define PHY_REG_BMCR        0x00        /* Basic Mode Control Register       */
#define PHY_REG_BMSR        0x01        /* Basic Mode Status Register        */
#define PHY_REG_IDR1        0x02        /* PHY Identifier 1                  */
#define PHY_REG_IDR2        0x03        /* PHY Identifier 2                  */
#define PHY_REG_ANAR        0x04        /* Auto-Negotiation Advertisement    */
#define PHY_REG_ANLPAR      0x05        /* Auto-Neg. Link Partner Abitily    */
#define PHY_REG_ANER        0x06        /* Auto-Neg. Expansion Register      */
#define PHY_REG_ANNPTR      0x07        /* Auto-Neg. Next Page TX            */

/* PHY Extended Registers */
#define PHY_REG_STS         0x10        /* Status Register                   */
#define PHY_REG_MICR        0x11        /* MII Interrupt Control Register    */
#define PHY_REG_MISR        0x12        /* MII Interrupt Status Register     */
#define PHY_REG_FCSCR       0x14        /* False Carrier Sense Counter       */
#define PHY_REG_RECR        0x15        /* Receive Error Counter             */
#define PHY_REG_PCSR        0x16        /* PCS Sublayer Config. and Status   */
#define PHY_REG_RBR         0x17        /* RMII and Bypass Register          */
#define PHY_REG_LEDCR       0x18        /* LED Direct Control Register       */
#define PHY_REG_PHYCR       0x19        /* PHY Control Register              */
#define PHY_REG_10BTSCR     0x1A        /* 10Base-T Status/Control Register  */
#define PHY_REG_CDCTRL1     0x1B        /* CD Test Control and BIST Extens.  */
#define PHY_REG_EDCR        0x1D        /* Energy Detect Control Register    */
#define PHY_REG_SPECIAL     0x1F        /* Special Control/Status LAN8720    */

#define PHY_FULLD_100M      0x2100      /* Full Duplex 100Mbit               */
#define PHY_HALFD_100M      0x2000      /* Half Duplex 100Mbit               */
#define PHY_FULLD_10M       0x0100      /* Full Duplex 10Mbit                */
#define PHY_HALFD_10M       0x0000      /* Half Duplex 10MBit                */
#define PHY_AUTO_NEG        0x3000      /* Select Auto Negotiation           */

#define DP83848C_DEF_ADR    0x0100      /* Default PHY device address        */
#define DP83848C_ID         0x20005C90  /* PHY Identifier                    */

/*************************************************
 * CodeRed - PHY definitions for RDB1768 rev 2
 * which uses SMSC LAN8720 PHY instead of DP83848C
 *************************************************/
#define LAN8720_ID          0x0007C0F0  /* PHY Identifier                    */

/* EMAC Memory Buffer configuration for 16K Ethernet RAM. (32K for LPC1769/8/7/6/5) */
#define NUM_RX_FRAG         10          /* Num.of RX Fragments 4*1536= 6.0kB */
#define NUM_TX_FRAG         10          /* Num.of TX Fragments 3*1536= 4.6kB */
#define ETH_FRAG_SIZE       1536        /* Packet Fragment size 1536 Bytes   */

#pragma pack(4)
// derived from UM10360, LPC17xx User manual, Rev.2 - 19 August 2010
struct _emacData
{
  struct
  { // Table 175
    void* Packet;
    // Table 176
    union
    {
      long Control;
      struct
      {
        long  Size:11;
        long  :20;
        long  Interrupt:1;
      } RX_DESC_STRUCT;
    } RX_DESC_UNION;
  } RxDescriptor[NUM_RX_FRAG];
  struct
  { // Table 177
    union
    {
      long  StatusInfo;
      struct
      { /* Table 179 */
        long  RxSize:11;
        long  :7;
        long  ControlFrame:1;
        long  VLAN:1;
        long  FailFilter:1;
        long  Multicast:1;
        long  Broadcast:1;
        long  CRCError:1;
        long  SymbolError:1;
        long  LengthError:1;
        long  RangeError:1;
        long  AlignmentError:1;
        long  Overrun:1;
        long  NoDescriptor:1;
        long LastFlag:1;
        long Error:1;
      } RX_STAT_STRUCT;
    } RX_STAT_UNION;
    union
    {
      long  StatusHashCRC;
      struct
      { // Table 178
        long  SAHashCRC:9;
        long  :7;
        long  DAHashCRC:9;
        long  :7;
      } S0;
    } U0;
  } RxStatus[NUM_RX_FRAG];
  unsigned char RxBuffer[NUM_RX_FRAG][ETH_FRAG_SIZE];
  struct
  { // Table 180
    void* Packet;
    union
    {
      long  Control;
      struct
      { // Table 181
        long  Size:11;
        long  :15;
        long  Override:1;
        long  Huge:1;
        long  Pad:1;
        long  CRC:1;
        long  Last:1;
        long  Interrupt:1;
      } TX_DESC_STRUCT;
    } TX_DESC_UNION;
  } TxDescriptor[NUM_TX_FRAG];
  struct
  { // Table 182
    union
    {
      long  StatusInfo;
      struct
      { // Table 18
        long  :21;
        long  CollisionCount:4;
        long  Defer:1;
        long  ExcessiveDefer:1;
        long  ExcessiveCollision:1;
        long  LateCollision:1;
        long  Underrun:1;
        long  NoDescriptor:1;
        long  Error:1;
      } TX_STAT_STRUCT;
    } TX_STAT_UNION;
  } TxStatus[NUM_TX_FRAG];
  unsigned char TxBuffer[NUM_TX_FRAG][ETH_FRAG_SIZE];
} *EMACDATA;
#pragma pack()

// NOTE: Verify that no data is declared anywhere else for the AHB SRAM section
static struct _emacData * const emacData=(struct _emacData *)0x2007C000;

// Ethernet network layer definitions
#define ETH_DA_OFS           0                   // Destination MAC address (48 Bit)
#define ETH_SA_OFS           6                   // Source MAC address (48 Bit)
#define ETH_TYPE_OFS         12                  // Type field (16 Bit)
#define ETH_DATA_OFS         14                  // Frame Data
#define ETH_HEADER_SIZE      14

#define FRAME_ARP            0x0806              // frame types (stored in Type/Length field)
#define FRAME_IP             0x0800

// IPv4 layer definitions
#define IP_VER_IHL_OFS       ETH_DATA_OFS + 0    // Version, Header Length
#define IP_TOS_OFS           ETH_DATA_OFS + 1    // Type of Service
#define IP_TOTAL_LENGTH_OFS  ETH_DATA_OFS + 2    // IP Frame's Total Length
#define IP_IDENT_OFS         ETH_DATA_OFS + 4    // Identifying Value
#define IP_FLAGS_FRAG_OFS    ETH_DATA_OFS + 6    // Flags and Fragment Offset
#define IP_TTL_PROT_OFS      ETH_DATA_OFS + 8    // Frame's Time to Live, Protocol
#define IP_TTL_OFS           ETH_DATA_OFS + 8    // Frame's Time to Live
#define IP_PROT_OFS          ETH_DATA_OFS + 9    // Frame's Protocol
#define IP_HEAD_CHKSUM_OFS   ETH_DATA_OFS + 10   // IP Frame's Header Checksum
#define IP_SOURCE_OFS        ETH_DATA_OFS + 12   // Source Address (32 Bit)
#define IP_DESTINATION_OFS   ETH_DATA_OFS + 16   // Destination Address (32 Bit)
#define IP_DATA_OFS          ETH_DATA_OFS + 20   // Frame Data (if no options)
#define IP_HEADER_SIZE       20                  // w/o options

#define IP_VER_IHL          0x45                // IPv4, Header Length = 5x32 bit
#define IP_TOS_D            0x10                // TOS low delay
#define IP_TOS_T            0x08                // TOS high throughput
#define IP_TOS_R            0x04                // TOS high reliability
// !! le compilateur Keil n'aime pas le binaire
#define IP_DSCP_AF11        10 //0b001010 !! "0b... " n'est pas compatible avec Keil compiler // Differentiated Services Code Point (RFC2474)
#define IP_DSCP_AF12        12 //0b001100
#define IP_DSCP_AF13        14 //0b001110
#define IP_DSCP_AF21        18 //0b010010
#define IP_DSCP_AF22        20 //0b010100
#define IP_DSCP_AF23        22 //0b010110
#define IP_DSCP_AF31        26 //0b011010
#define IP_DSCP_AF32        28 //0b011100
#define IP_DSCP_AF33        30 //0b011110
#define IP_DSCP_AF41        34 //0b100010
#define IP_DSCP_AF42        36 //0b100100
#define IP_DSCP_AF43        38 //0b100110
#define IP_DSCP_BE          0  //0b000000
#define IP_DSCP_CS1         8  //0b001000
#define IP_DSCP_CS2         16 //0b010000
#define IP_DSCP_CS3         24 //0b011000
#define IP_DSCP_CS4         32 //0b100000
#define IP_DSCP_CS5         40 //0b101000
#define IP_DSCP_CS6         48 //0b110000
#define IP_DSCP_CS7         56 //0b111000
#define IP_DSCP_EF          46 //0b101110
#define IP_DSCP_NC1         48 //0b110000
#define IP_DSCP_NC2         56 //0b111000
#define IP_FLAG_DONTFRAG     0x4000              // don't fragment IP frame
#define IP_FLAG_MOREFRAG     0x2000              // more fragments available
#define IP_FRAGOFS_MASK      0x1FFF              // indicates where this fragment belongs

#define PROT_ICMP            1                   // Internet Control Message Protocol
#define PROT_TCP             6                   // Transmission Control Protocol
#define PROT_UDP             17                  // User Datagram Protocol

// ARP definitions
#define ARP_HARDW_OFS        ETH_DATA_OFS + 0    // Hardware address type
#define ARP_PROT_OFS         ETH_DATA_OFS + 2    // Protocol
#define ARP_HLEN_PLEN_OFS    ETH_DATA_OFS + 4    // byte length of each hardw. / prot. address
#define ARP_OPCODE_OFS       ETH_DATA_OFS + 6    // Opcode
#define ARP_SENDER_HA_OFS    ETH_DATA_OFS + 8    // Hardw. address of sender of this packet
#define ARP_SENDER_IP_OFS    ETH_DATA_OFS + 14   // IP address of sender
#define ARP_TARGET_HA_OFS    ETH_DATA_OFS + 18   // Hardw. address of target of this packet
#define ARP_TARGET_IP_OFS    ETH_DATA_OFS + 24   // IP address of target
#define ARP_FRAME_SIZE       28

#define HARDW_ETH10          1                   // hardware-type 10Mbps Ethernet
#define IP_HLEN_PLEN         0x0604              // MAC = 6 byte long, IP = 4 byte long
#define OP_ARP_REQUEST       1                   // operations for ARP-frames
#define OP_ARP_ANSWER        2

// ICMP definitions
#define ICMP_TYPE_OFS        IP_DATA_OFS + 0     // type of message
#define ICMP_CODE_OFS        IP_DATA_OFS + 1     // code of message
#define ICMP_CHKSUM_OFS      IP_DATA_OFS + 2     // checksum of ICMP-message (16 bit)
#define ICMP_DATA_OFS        IP_DATA_OFS + 4
#define ICMP_HEADER_SIZE     4

#define ICMP_ECHO            8                   // message is an echo request
#define ICMP_ECHO_REPLY      0                   // message is an echo reply

// UDP layer definitions
#define UDP_SRCPORT_OFS      IP_DATA_OFS + 0     // Source Port (16 bit)
#define UDP_DESTPORT_OFS     IP_DATA_OFS + 2     // Destination Port (16 bit)
#define UDP_LEN_OFS          IP_DATA_OFS + 4     // Length of UDP packet (16 bit)
#define UDP_CHKSUM_OFS       IP_DATA_OFS + 6     // Acknowledge Number (32 bit)
#define UDP_DATA_OFS         IP_DATA_OFS + 8     // Frame Data (if no options)
#define UDP_HEADER_SIZE      8                   // size w/o options

#define MAX_UDP_TX_DATA_SIZE 1024                // max. outgoing UDP data size (even!)
#define MAX_UDP_RX_DATA_SIZE 256                 // max. incoming UDP data size (even!)

#define UDPIP_SERVICES 4
static  struct
{
  unsigned short  LocalPort;
  void (*Callback)(unsigned char* msg, short len, unsigned char broadcast);
  unsigned char   RemoteMAC[6]; // MAC address to reply to
  unsigned long   RemoteIPv4;   // IP address to reply to
  unsigned short  RemotePort;   // Port to reply to
} Services[UDPIP_SERVICES];

static  unsigned char   LocalMAC[6]= {0x00,0x11,0x11,0x1a,0x5a,0x4b}; //{'A','J','A','B','O','1'};
static  unsigned long   LocalIPv4=0L;
static  unsigned char   RemoteMAC[6];
static  unsigned long   RemoteIPv4;
static  unsigned short  RemotePort;
static  unsigned short  ReceivedIPLength;         // 16 bit IP packet length
static  unsigned char   Broadcast;

static  unsigned char*  RxBuffer;

#pragma pack(2)
static struct
{
  unsigned char SrcMAC[6];
  unsigned long SrcIPv4;
  unsigned char DstMAC[6];
  unsigned long DstIPv4;
} ArpLast;
#pragma pack()

static unsigned short CalcChecksum(void *Start, unsigned short Count)
{
  unsigned short *pStart;
  unsigned long Sum = 0;

  pStart = Start;
  while (Count > 1) {                            // sum words
    Sum += *pStart++;
    Count -= 2;
  }

  if (Count)                                     // add left-over byte, if any
    Sum += *(unsigned char *)pStart;


  while (Sum >> 16)                              // fold 32-bit sum to 16 bits
    Sum = (Sum & 0xFFFF) + (Sum >> 16);

  return ~Sum;
}


static void PrepareARP_ANSWER(void)
{
  unsigned int    index;
  unsigned int    next_index;
  unsigned char*  txbuf;

  index  = LPC_EMAC->TxProduceIndex;
  if (index==LPC_EMAC->TxDescriptorNumber)
    next_index=0;
  else
    next_index=index+1;

  if (next_index==LPC_EMAC->TxConsumeIndex) return; // too bad, no room to answer

  txbuf = emacData->TxBuffer[index];
  // Ethernet
  memcpy(&txbuf[ETH_DA_OFS], &RemoteMAC, 6);
  memcpy(&txbuf[ETH_SA_OFS], &LocalMAC, 6);
  *(unsigned short *)&txbuf[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);

  // ARP
  *(unsigned short *)&txbuf[ARP_HARDW_OFS] = SWAPB(HARDW_ETH10);
  *(unsigned short *)&txbuf[ARP_PROT_OFS] = SWAPB(FRAME_IP);
  *(unsigned short *)&txbuf[ARP_HLEN_PLEN_OFS] = SWAPB(IP_HLEN_PLEN);
  *(unsigned short *)&txbuf[ARP_OPCODE_OFS] = SWAPB(OP_ARP_ANSWER);
  memcpy(&txbuf[ARP_SENDER_HA_OFS], &LocalMAC, 6);
  memcpy(&txbuf[ARP_SENDER_IP_OFS], &LocalIPv4, 4);
  memcpy(&txbuf[ARP_TARGET_HA_OFS], &RemoteMAC, 6);
  memcpy(&txbuf[ARP_TARGET_IP_OFS], &RemoteIPv4, 4);

  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Size=ETH_HEADER_SIZE + ARP_FRAME_SIZE;
  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Last=1;
  LPC_EMAC->TxProduceIndex = next_index;
}

static void PrepareICMP_ECHO_REPLY(void)
{
  unsigned int    index;
  unsigned int    next_index;
  unsigned char*  txbuf;
  unsigned short ICMPDataCount;
  index  = LPC_EMAC->TxProduceIndex;
  if (index==LPC_EMAC->TxDescriptorNumber)
    next_index=0;
  else
    next_index=index+1;

  if (next_index==LPC_EMAC->TxConsumeIndex) return; // too bad, no room to answer

  txbuf = emacData->TxBuffer[index];


  ICMPDataCount = ReceivedIPLength - IP_HEADER_SIZE - ICMP_HEADER_SIZE;

  // Ethernet
  memcpy(&txbuf[ETH_DA_OFS], &RemoteMAC, 6);
  memcpy(&txbuf[ETH_SA_OFS], &LocalMAC, 6);

  *(unsigned short *)&txbuf[ETH_TYPE_OFS] = SWAPB(FRAME_IP);

  // IP
  txbuf[IP_VER_IHL] = IP_VER_IHL;
  *(unsigned short *)&txbuf[IP_TOTAL_LENGTH_OFS]=SWAPB(IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount);
  *(unsigned short *)&txbuf[IP_IDENT_OFS] = 0;
  *(unsigned short *)&txbuf[IP_FLAGS_FRAG_OFS] = 0;
  *(unsigned short *)&txbuf[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_ICMP);
  *(unsigned short *)&txbuf[IP_HEAD_CHKSUM_OFS] = 0;
  memcpy(&txbuf[IP_SOURCE_OFS], &LocalIPv4, 4);
  memcpy(&txbuf[IP_DESTINATION_OFS], &RemoteIPv4, 4);
  *(unsigned short *)&txbuf[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&txbuf[IP_VER_IHL_OFS], IP_HEADER_SIZE);

  // ICMP
  txbuf[ICMP_TYPE_OFS] = ICMP_ECHO_REPLY;
  txbuf[ICMP_CODE_OFS] = 0;

  *(unsigned short *)&txbuf[ICMP_CHKSUM_OFS] = 0;                   // initialize checksum field

  memcpy(&txbuf[ICMP_DATA_OFS],&RxBuffer[ICMP_DATA_OFS], ICMPDataCount);       // copy received data
  *(unsigned short *)&txbuf[ICMP_CHKSUM_OFS] = CalcChecksum(&txbuf[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE);

  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Size=ETH_HEADER_SIZE + IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount;
  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Last=1;
  LPC_EMAC->TxProduceIndex = next_index;
}

static void ProcessICMP(void)
{
  switch (RxBuffer[ICMP_TYPE_OFS])
  {                // check type
    case ICMP_ECHO :                             // is echo request?
    {
      PrepareICMP_ECHO_REPLY();                  // echo as much as we can...
      break;
    }
  }
}

static void ProcessUDP(void)
{
//printf("PROCESS UDP\n");
// UNSIGNED devant les 2 lignes suivantes
  unsigned short LocalPort = SWAPB(*(unsigned short *)&RxBuffer[UDP_DESTPORT_OFS]);
  unsigned short Length = SWAPB(*(unsigned short *)&RxBuffer[UDP_LEN_OFS]);
  RemotePort = SWAPB(*(unsigned short *)&RxBuffer[UDP_SRCPORT_OFS]);
  // checksum = SWAPB(*(unsigned short *)&RxBuffer[UDP_CHKSUM_OFS]);
  if (Length<=MAX_UDP_RX_DATA_SIZE)
  {
    short i;
    for (i=0;i<UDPIP_SERVICES;i++)
    {
//printf("\tServices[i].LocalPort=[%u], LocalPort=[%u]\n", Services[i].LocalPort, LocalPort);
      if (Services[i].LocalPort==LocalPort)
      {
        // simple callback mechanism, callback function should already
        // know which service index to use
//printf("CALL BACK\n");
        if (Services[i].Callback)
         Services[i].Callback(&RxBuffer[UDP_DATA_OFS],Length-UDP_HEADER_SIZE,Broadcast);
      }
    }
  }
}

static void ProcessFrame(void)
{
  unsigned long DestIPv4;
  unsigned char ProtocolType;

//printf("PROCESS FRAME\n");

  // handle ARP frames or IP frames
  switch (*(unsigned short*)&RxBuffer[ETH_TYPE_OFS])
  {
    case SWAPB(FRAME_ARP):
//printf("\tFRAME ARP\n");
      // don't care if broadcasted or not
      if (*(unsigned short*)&RxBuffer[ARP_HARDW_OFS] == SWAPB(HARDW_ETH10))   // Ethernet frame
        if (*(unsigned short*)&RxBuffer[ARP_PROT_OFS] == SWAPB(FRAME_IP))      // check protocol
          if (*(unsigned short*)&RxBuffer[ARP_HLEN_PLEN_OFS] == SWAPB(IP_HLEN_PLEN))     // check HLEN, PLEN
            if (*(unsigned short*)&RxBuffer[ARP_OPCODE_OFS] == SWAPB(OP_ARP_REQUEST))
            {
              memcpy(&ArpLast.SrcMAC,&RxBuffer[ARP_SENDER_HA_OFS],6);
              ArpLast.SrcIPv4=*(unsigned long*)&RxBuffer[ARP_SENDER_IP_OFS];
              memcpy(&ArpLast.DstMAC,&RxBuffer[ARP_TARGET_HA_OFS],6);
              ArpLast.DstIPv4=*(unsigned long*)&RxBuffer[ARP_TARGET_IP_OFS];

              if (LocalIPv4==ArpLast.DstIPv4)           // is it for us?
              {
//printf("\tPOUR NOUS LocalIPV4=[%u] ArpLast.DstIPv4=[%u]\n", LocalIPv4, ArpLast.DstIPv4);
                  PrepareARP_ANSWER();                    // yes->create ARP_ANSWER frame
              }
//              else
//              {
//printf("\tPAS POUR NOUS LocalIPV4=[%u] ArpLast.DstIPv4=[%u]\n", LocalIPv4, ArpLast.DstIPv4);
//               }
            }
      break;
    case SWAPB(FRAME_IP):
    {
//printf("\tFRAME IP\n");
      if (RxBuffer[IP_VER_IHL_OFS] == IP_VER_IHL)       // IPv4, IHL=5 (20 Bytes Header)
      {
        // ignore Type Of Service
        ReceivedIPLength = SWAPB(*(unsigned short*)&RxBuffer[IP_TOTAL_LENGTH_OFS]);
        // ignore identification

        if (!(*(unsigned short*)&RxBuffer[IP_FLAGS_FRAG_OFS] & SWAPB((IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK))))  // only unfragm. frames
        {
          ProtocolType = RxBuffer[IP_PROT_OFS];  // ignore TTL
          // ignore checksum
          RemoteIPv4=*(unsigned long*)&RxBuffer[IP_SOURCE_OFS];
          DestIPv4=*(unsigned long*)&RxBuffer[IP_DESTINATION_OFS];

          if (Broadcast)
          {
            switch (ProtocolType)
            {
              case PROT_UDP  : { ProcessUDP(); break; }     // same handling for broadcast as for directed udp
            }
          }
          else if (LocalIPv4==DestIPv4)                 // is it for us?
            switch (ProtocolType)
            {
              case PROT_ICMP : { ProcessICMP(); break; }
              case PROT_TCP  : { /*ProcessTCPFrame();*/ break; }  // No TCP today
              case PROT_UDP  : { ProcessUDP(); break; }
            }
        }
      }
//      else
//    ﻿    printf("\t!!! RIEN !!!\n");
      break;
    }
  }
}

static void WriteToPHY (int reg, int writeval)
{
  unsigned int loop;
  // Set up address to access in MII Mgmt Address Register
  LPC_EMAC->MADR = DP83848C_DEF_ADR | reg;
  // Write value into MII Mgmt Write Data Register
  LPC_EMAC->MWTD = writeval;
  // Loop whilst write to PHY completes
  for (loop = 0; loop < MII_WR_TOUT; loop++) {
    if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; }
  }
}

static unsigned short ReadFromPHY (unsigned char reg)
{
  unsigned int loop;
  // Set up address to access in MII Mgmt Address Register
  LPC_EMAC->MADR = DP83848C_DEF_ADR | reg;
  // Trigger a PHY read via MII Mgmt Command Register
  LPC_EMAC->MCMD = MCMD_READ;
  // Loop whilst read from PHY completes
  for (loop = 0; loop < MII_RD_TOUT; loop++) {
    if ((LPC_EMAC->MIND & MIND_BUSY) == 0)  { break; }
  }
  LPC_EMAC->MCMD = 0; // Cancel read
  // Returned value is in MII Mgmt Read Data Register
  return (LPC_EMAC->MRDD);
}

// Ethernet power/clock control bit in PCONP register
#define PCENET 0x40000000
// Ethernet configuration for PINSEL2, as per user guide section 5.3
#define ENET_PINSEL2_CONFIG 0x50150105
// Ethernet configuration for PINSEL3, as per user guide section 5.4
#define ENET_PINSEL3_CONFIG 0x00000005
// Only bottom byte of PINSEL3 relevant to Ethernet
#define ENET_PINSEL3_MASK 0x0000000F

static  void initDP83848C()
{
  volatile unsigned int loop;
  unsigned int value;

  // Set PHY to autonegotiation link speed
  WriteToPHY (PHY_REG_BMCR, PHY_AUTO_NEG);
  // loop until autonegotiation completes
  for (loop = 0; loop < 0x100000; loop++)
  {
    value = ReadFromPHY (PHY_REG_BMSR);
    if (value & 0x0020)
    {
      // Autonegotiation has completed
      break;
    }
  }

  // Now check the link status
  for (loop = 0; loop < 0x10000; loop++)
  {
    value = ReadFromPHY (PHY_REG_STS);
    if (value & 0x0001)
    {
      // The link is on
      break;
    }
  }

  // this status also contains duplex and speed info
  // Now configure for full/half duplex mode
  if (value & 0x0004)
  {
    // We are in full duplex is enabled mode
    LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
    LPC_EMAC->Command |= CR_FULL_DUP;
    LPC_EMAC->IPGT     = IPGT_FULL_DUP;
  }
  else
  {
    // Otherwise we are in half duplex mode
    LPC_EMAC->IPGT = IPGT_HALF_DUP;
  }
  // Now configure 100MBit or 10MBit mode
  if (value & 0x0002)
  {
    // 10MBit mode
    LPC_EMAC->SUPP = 0;
  }
  else
  {
    // 100MBit mode
    LPC_EMAC->SUPP = SUPP_SPEED;
  }
}

static  void  initLAN8720()
{
  volatile unsigned int loop;
  unsigned int value;

  // Set PHY to autonegotiation link speed
  WriteToPHY (PHY_REG_BMCR, PHY_AUTO_NEG);
  // loop until autonegotiation completes
  for (loop = 0; loop < 0x100000; loop++)
  {
    value = ReadFromPHY (PHY_REG_BMSR);
    if (value & 0x0020)
    {
      // Autonegotiation has completed
      break;
    }
  }

  // Now check the link status
  for (loop = 0; loop < 0x10000; loop++)
  {
    value = ReadFromPHY (PHY_REG_BMSR);
    if (value & 0x0004)
    {
      // The link is on
      break;
    }
  }

  // what is the link like?
  value = ReadFromPHY(PHY_REG_SPECIAL);
  // Now configure for full/half duplex mode
  if ( value & 16) // JEA (value & 0b10000)
  {
    // We are in full duplex is enabled mode
    LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
    LPC_EMAC->Command |= CR_FULL_DUP;
    LPC_EMAC->IPGT     = IPGT_FULL_DUP;
  }
  else
  {
    // Otherwise we are in half duplex mode
    LPC_EMAC->IPGT = IPGT_HALF_DUP;
  }
  // Now configure 100MBit or 10MBit mode
  if (value & 8) //JEA (value & 0b01000)
  {
    // 100MBit mode
    LPC_EMAC->SUPP = SUPP_SPEED;
  }
  else
  {
    // 10MBit mode
    LPC_EMAC->SUPP = 0;
  }

}

void udpipInit(unsigned char* mymac, unsigned long myip)
{
  volatile unsigned int loop;
  unsigned int value=0, phyid1, phyid2;
  short i;
  memcpy(LocalMAC,mymac,6);
  LocalIPv4=myip;

  // Set Ethernet power/clock control bit
  LPC_SC->PCONP |= PCENET;

  //Enable Ethernet pins through PINSEL registers
  LPC_PINCON->PINSEL2 = ENET_PINSEL2_CONFIG;
  LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~(ENET_PINSEL3_MASK)) | ENET_PINSEL3_CONFIG;

  // Set up MAC Configuration Register 1
  LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX |
         MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES;

  // Set up MAC Command Register
  LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;

  // Short delay
  for (loop = 100; loop; loop--);

  // Set up MAC Configuration Register 1 to pass all receive frames
  LPC_EMAC->MAC1 = MAC1_PASS_ALL;
  // Set up MAC Configuration Register 2 to append CRC and pad out frames
  LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;

  // Set Ethernet Maximum Frame Register
  LPC_EMAC->MAXF = ETH_MAX_FLEN;
  // Set Collision Window / Retry Register
  LPC_EMAC->CLRT = CLRT_DEF;
  // Set Non Back-to-Back Inter-Packet-Gap Register
  LPC_EMAC->IPGR = IPGR_DEF;

     /* Enable Reduced MII interface. */
    LPC_EMAC->MCFG = MCFG_CLK_DIV48 | MCFG_RES_MII;
     for (loop = 100; loop; loop--);
     LPC_EMAC->MCFG = MCFG_CLK_DIV48;

   // Set MAC Command Register to enable Reduced MII interface
   // and prevent runt frames being filtered out
  LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;

  // Put DP83848C PHY into reset mode
  WriteToPHY (PHY_REG_BMCR, 0x8000);

  // Loop until hardware reset completes
  for (loop = 0; loop < 0x100000; loop++) {
    value = ReadFromPHY (PHY_REG_BMCR);
    if (!(value & 0x8000)) {
      // Reset has completed
      break;
    }
  }

  // Just check this actually is a DP83848C PHY
  phyid1 = ReadFromPHY (PHY_REG_IDR1);
  phyid2 = ReadFromPHY (PHY_REG_IDR2);

  if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DP83848C_ID)
    initDP83848C();
  else if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == LAN8720_ID)
    initLAN8720();
  else
    return;

  // Now set the Ethernet MAC Address registers
  // NOTE - MAC address must be unique on the network!
  LPC_EMAC->SA0 = (mymac[0] << 8) | mymac[1]; // Station address 0 Reg
  LPC_EMAC->SA1 = (mymac[2] << 8) | mymac[3]; // Station address 1 Reg
  LPC_EMAC->SA2 = (mymac[4] << 8) | mymac[5]; // Station address 2 Reg

  for (i=0;i<NUM_RX_FRAG;i++)
  {
    emacData->RxDescriptor[i].Packet=emacData->RxBuffer[i];
    emacData->RxDescriptor[i].RX_DESC_UNION.RX_DESC_STRUCT.Size=ETH_FRAG_SIZE-1;
    emacData->RxDescriptor[i].RX_DESC_UNION.RX_DESC_STRUCT.Interrupt=0;
    emacData->RxStatus[i].RX_STAT_UNION.StatusInfo=0;
    emacData->RxStatus[i].U0.StatusHashCRC=0; // RX_STAT_UNION ou U0 ???
  }
  for (i=0;i<NUM_TX_FRAG;i++)
  {
    emacData->TxDescriptor[i].Packet=emacData->TxBuffer[i];
    emacData->TxDescriptor[i].TX_DESC_UNION.Control=0;
    emacData->TxStatus[i].TX_STAT_UNION.StatusInfo=0;
  }
  // Set EMAC registers to point into emacData
  LPC_EMAC->RxDescriptor=(long)&emacData->RxDescriptor;
  LPC_EMAC->RxStatus=(long)&emacData->RxStatus;
  LPC_EMAC->RxDescriptorNumber=NUM_RX_FRAG-1;
  LPC_EMAC->RxConsumeIndex=0;
  LPC_EMAC->TxDescriptor=(long)&emacData->TxDescriptor;
  LPC_EMAC->TxStatus=(long)&emacData->TxStatus;
  LPC_EMAC->TxDescriptorNumber=NUM_TX_FRAG-1;
  LPC_EMAC->TxProduceIndex=0;

  // Receive Broadcast and Perfect Match Packets
  LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN;

  // Enable interrupts MAC Module Control Interrupt Enable Register
  LPC_EMAC->IntEnable = 0x00;//INT_RX_DONE | INT_TX_DONE;

  // Reset all ethernet interrupts in MAC module
  LPC_EMAC->IntClear  = 0xFFFF;

  // Finally enable receive and transmit mode in ethernet core
  LPC_EMAC->Command  |= (CR_RX_EN | CR_TX_EN);
  LPC_EMAC->MAC1     |= MAC1_REC_EN;
}

void udpipExit(void)
{
  // Disable all interrupt
  LPC_EMAC->IntEnable = 0x00;
  // Clear all pending interrupt
  LPC_EMAC->IntClear = 0xFFFF;

  // Reset Ethernet power/clock control bit
  LPC_SC->PCONP &= ~PCENET;
}

void udpipWork(void)
{
  // Check to see if packet received
  if (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex)
  {
/*
    if (LPC_EMAC->SUPP&0x100)
      udpipActivity100MOn();
    else
      udpipActivity10MOn();
*/
    unsigned char DestMAC[6]; // to hold 48 bit MAC address
    short i;
    short index = LPC_EMAC->RxConsumeIndex;
    // ReceiveLength = emacData->RxStatus[index].RxSize - 3;
    RxBuffer = emacData->RxBuffer[index];

    // Read destination address
    memcpy(&DestMAC,&RxBuffer[ETH_DA_OFS],6);
    // Save it for ProcessFrame
    memcpy(&RemoteMAC,&RxBuffer[ETH_SA_OFS],6);

    Broadcast=1;
    for (i=0;i<6;i++)
      if (DestMAC[i]!=0xff)
      {
        Broadcast=0;
        break;
      }

    ProcessFrame();

    // now release ethernet controller buffer
    if (index==LPC_EMAC->RxDescriptorNumber)
      LPC_EMAC->RxConsumeIndex=0;
    else
      LPC_EMAC->RxConsumeIndex=index+1;
 //   udpipActivityOff();
  }
}


short udpipSend(short idx, void* buf, short len)
{
  unsigned int    index;
  unsigned int    next_index;
  unsigned char*  txbuf;
  if (idx<0 || idx>=UDPIP_SERVICES) return -1;

// A quoi ca sert ?
/*  if (LPC_EMAC->SUPP&0x100)
    udpipActivity100MOn();
  else
    udpipActivity10MOn(); */

  index  = LPC_EMAC->TxProduceIndex;
  if (index==LPC_EMAC->TxDescriptorNumber)
    next_index=0;
  else
    next_index=index+1;

  if (next_index==LPC_EMAC->TxConsumeIndex) return -2;

  txbuf = emacData->TxBuffer[index];

  // Ethernet
  memcpy(&txbuf[ETH_DA_OFS], &Services[idx].RemoteMAC, 6);
  memcpy(&txbuf[ETH_SA_OFS], &LocalMAC, 6);

  *(unsigned short *)&txbuf[ETH_TYPE_OFS] = SWAPB(FRAME_IP);

  // IP
  //txbuf[IP_TOS_OFS] = IP_TOS_D; // Jea, ligne commentee dans la version originale
  txbuf[IP_VER_IHL_OFS] = IP_VER_IHL;
  txbuf[IP_TOS_OFS] = IP_DSCP_CS7;
  *(unsigned short *)&txbuf[IP_TOTAL_LENGTH_OFS]=SWAPB(IP_HEADER_SIZE + UDP_HEADER_SIZE + len);
  *(unsigned short *)&txbuf[IP_IDENT_OFS] = 0;
  *(unsigned short *)&txbuf[IP_FLAGS_FRAG_OFS] = 0;
  *(unsigned short *)&txbuf[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_UDP);
  *(unsigned short *)&txbuf[IP_HEAD_CHKSUM_OFS] = 0;
  memcpy(&txbuf[IP_SOURCE_OFS], &LocalIPv4, 4);
  memcpy(&txbuf[IP_DESTINATION_OFS], &Services[idx].RemoteIPv4, 4);
  *(unsigned short *)&txbuf[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&txbuf[IP_VER_IHL_OFS], IP_HEADER_SIZE);

  // UDP
  *(unsigned short *)&txbuf[UDP_SRCPORT_OFS]=SWAPB(Services[idx].LocalPort);
  *(unsigned short *)&txbuf[UDP_DESTPORT_OFS]=SWAPB(Services[idx].RemotePort);
  *(unsigned short *)&txbuf[UDP_LEN_OFS]=SWAPB(len+UDP_HEADER_SIZE);
  *(unsigned short *)&txbuf[UDP_CHKSUM_OFS]=0;
  memcpy(&txbuf[UDP_DATA_OFS],buf,len);

  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Size=ETH_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE+len;
  emacData->TxDescriptor[index].TX_DESC_UNION.TX_DESC_STRUCT.Last=1;
  //emacData->TxDescriptor[index].Size=ETH_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE+len;
  //emacData->TxDescriptor[index].Last=1;
  LPC_EMAC->TxProduceIndex = next_index;

  //A quoi ca sert ?
  //udpipActivityOff();
 return 0;
}


short udpipSetService(short idx, unsigned short port, void (*callback)(unsigned char* msg, short len, unsigned char broadcast))
{
 if (idx<0 || idx>=UDPIP_SERVICES) return -1;
  Services[idx].LocalPort=port;
  Services[idx].Callback=callback;
  // callback function should know the service index, since
  // this callback is especially set for it
  // when first message is received for LocalPort, the RemoteXXXX fields will be set
printf("udpipSetService Func done\n");
  return 0;
}

void udpipSaveRemoteForService(short idx)
{
 char strMAC[32];
  if (idx<0 || idx>=UDPIP_SERVICES) return;
  memcpy(Services[idx].RemoteMAC,RemoteMAC,6);
  sprintf(strMAC, "%02x:%02x:%02x:%02x:%02x:%02x", RemoteMAC[0], RemoteMAC[1], RemoteMAC[2], RemoteMAC[3], RemoteMAC[4], RemoteMAC[5]);
printf("REMOTE MAC int = %d, char = %s\n", RemoteMAC, strMAC);
  Services[idx].RemoteIPv4=RemoteIPv4;
  Services[idx].RemotePort=RemotePort;
printf("udpipSaveRemoteForService Func done\n");
}

short udpipRemoteIsRemoteForService(short idx)
{
  if (idx<0 || idx>=UDPIP_SERVICES) return 0;
  if (0!=memcmp(Services[idx].RemoteMAC,RemoteMAC,6)) return 0;
  if (Services[idx].RemoteIPv4!=RemoteIPv4) return 0;
  if (Services[idx].RemotePort!=RemotePort) return 0;
  return -1;
}

void udpipSetBroadcastForService(short idx, unsigned short port)
{
  if (idx<0 || idx>=UDPIP_SERVICES) return;
  Services[idx].RemoteIPv4=0xffffffff;
  memset(Services[idx].RemoteMAC,255,6);
  Services[idx].RemotePort=port;
printf("udpipSetBroadcastForService Func done\n");
}
